package com.mnemonic.views.field;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import javax.swing.JPanel;

import com.mnemonic.game.Game;
import com.mnemonic.views.GameAudio;
import com.mnemonic.views.GamePage;
import com.mnemonic.views.MainPage;

/**
 * 雷区
 * 
 * @author lifeng
 * @date 2021/05/14
 */
public class MineFields extends JPanel {

    private static final long serialVersionUID = 1L;

    /**
     * 游戏数据
     */
    protected Game game;

    /**
     * 游戏区域
     */
    protected GamePage gameField;

    /**
     * 每个单元格的大小
     */
    protected int size = 20;

    /**
     * 当前是否透视
     */
    protected volatile boolean penetrateFlag = false;

    /**
     * 状态位
     */
    private Image[] images = {Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("0.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("1.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("2.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("3.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("4.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("5.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("6.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("7.jpg")),
        Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("8.jpg")),};

    /**
     * 状态位
     */
    private Image mineBg = Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("bg.png"));
    private Image mineImage = Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("bomb.jpg"));
    private Image bombImage = Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("bomb0.jpg"));
    private Image flagImage = Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("flag.jpg"));
    private Image questionImage = Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("flag2.jpg"));
    private Image initImage = Toolkit.getDefaultToolkit().getImage(MainPage.class.getResource("init.jpg"));

    /**
     * 爆炸效果
     */
    private List<ExplodeField> explodes;

    /**
     * 开启线程来一直重绘雷区
     */
    private volatile boolean running = true;

    /**
     * 创建雷区
     * 
     * @param game
     */
    public MineFields(GamePage gameField, Game game) {
        this.gameField = gameField;
        this.game = game;
        this.explodes = new CopyOnWriteArrayList<ExplodeField>();

        // 添加点击事件
        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                MineFields.this.opsMouseClicked(e);
            }
        });

        // 一直重绘
        new Thread(() -> {
            while (running) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e1) {
                }
                this.repaint();
            }
        }).start();
    }

    /**
     * 将雷区绘制
     */
    @Override
    public void paint(Graphics g) {

        // 是否在运行中
        if (!this.running) {
            return;
        }

        // 绘制基本的组件
        super.paint(g);

        // 画背景，不是必须的
        this.doPaintBg(g);

        // 绘制雷区 透视
        if (this.penetrateFlag) {
            this.doPenetratePaint(g);

        }
        // 绘制雷区 非透视
        else {
            this.doPaint(g);
        }

        // 绘制爆炸效果
        this.doPaintExplodes(g);
    }

    /**
     * 画背景，不是必须的
     * 
     * @param g
     */
    private void doPaintBg(Graphics g) {
        Rectangle rectangle = this.getBounds();
        g.drawImage(mineBg, 0, 0, rectangle.width, rectangle.height, this);
    }

    /**
     * 画雷区 -- 透视图
     * 
     * @param g
     */
    private void doPenetratePaint(Graphics g) {
        int rows = this.game.getLevel().getRow();
        int cols = this.game.getLevel().getCol();
        int[][] mineMap = this.game.getMineMap();

        int j = 0;
        for (int i = 0; i < rows; ++i) {
            for (j = 0; j < cols; ++j) {
                if ((mineMap[i][j] & 0b00000001) == 1) {
                    if ((mineMap[i][j] & 0b00000110) == 0b00000100) {
                        g.drawImage(mineImage, j * size + 4, i * size + 50, size, size, this);
                    } else {
                        g.drawImage(bombImage, j * size + 4, i * size + 50, size, size, this);
                    }
                } else if (((mineMap[i][j] >>> 3) == 0)) {
                    g.drawImage(images[0], j * size + 4, i * size + 50, size, size, this);
                } else {
                    g.drawImage(images[mineMap[i][j] >>> 3], j * size + 4, i * size + 50, size, size, this);
                }
            }
        }

        g.setColor(Color.gray);
        for (int i = 0; i <= rows; ++i) {
            g.drawLine(4, i * size + 50, cols * size + 4, i * size + 50);
        }

        for (int i = 0; i < cols; ++i) {
            g.drawLine(i * size + 4, 50, i * size + 4, rows * size + 50);
        }
    }

    /**
     * 画雷区 -- 透视图
     * 
     * @param g
     */
    private void doPaint(Graphics g) {
        int rows = this.game.getLevel().getRow();
        int cols = this.game.getLevel().getCol();
        int[][] mineMap = this.game.getMineMap();

        int j = 0;
        for (int i = 0; i < rows; ++i) {
            for (j = 0; j < cols; ++j) {
                if ((mineMap[i][j] & 0b00000110) == 0) {
                    g.drawImage(initImage, j * size + 4, i * size + 50, size, size, this);
                } else if ((mineMap[i][j] & 0b00000110) == 0b00000010) {
                    if ((mineMap[i][j] & 0b00000001) == 1) {
                        g.drawImage(mineImage, j * size + 4, i * size + 50, size, size, this);
                    } else if (((mineMap[i][j] >>> 3) == 0)) {
                        g.drawImage(images[0], j * size + 4, i * size + 50, size, size, this);
                    } else {
                        g.drawImage(images[mineMap[i][j] >>> 3], j * size + 4, i * size + 50, size, size, this);
                    }
                } else if ((mineMap[i][j] & 0b00000110) == 0b000000100) {
                    g.drawImage(flagImage, j * size + 4, i * size + 50, size, size, this);
                } else if ((mineMap[i][j] & 0b00000110) == 0b000000110) {
                    g.drawImage(questionImage, j * size + 4, i * size + 50, size, size, this);
                }
            }
        }

        g.setColor(Color.gray);
        for (int i = 0; i <= rows; ++i) {
            g.drawLine(4, i * size + 50, cols * size + 4, i * size + 50);
        }

        for (int i = 0; i < cols; ++i) {
            g.drawLine(i * size + 4, 50, i * size + 4, rows * size + 50);
        }
    }

    /**
     * 执行透视操作
     */
    public void opsPenetrate() {
        this.penetrateFlag = !this.penetrateFlag;
        this.repaint();
    }

    /**
     * 排雷操作的入口
     * 
     * @param e
     */
    public void opsMouseClicked(MouseEvent e) {

        // 游戏数据
        int rows = this.game.getLevel().getRow();
        int cols = this.game.getLevel().getCol();
        int[][] mineMap = this.game.getMineMap();

        // 雷区
        int row = (e.getY() - 50) / size;
        int col = (e.getX() - 4) / size;

        /**
         * 其他区域
         */
        if (row * col < 0 || row > rows - 1 || col > cols - 1) {
            return;
        }

        /**
         * 双击事件
         */
        if (e.getClickCount() == 2) {
            return;
        }

        /**
         * 这个分支是滚轮 不用处理
         */
        if (e.getButton() == 2) {
            return;
        }

        /**
         * 已经打开不需要处理 <br>
         * 过滤：<br>
         * 011 踩雷<br>
         * 010 打开<br>
         * 放行：<br>
         * 10X 插旗<br>
         * 11X 疑问<br>
         */
        if ((mineMap[row][col] & 0b00000110) == 0b00000010) {
            return;
        }

        /**
         * 左键
         */
        if (e.getButton() == 1) {

            /**
             * 踩过的雷不用处理
             */
            if ((mineMap[row][col] & 0b00000111) == 0b00000011) {
                return;
            }

            /**
             * 插旗的地方不用处理
             */
            else if ((mineMap[row][col] & 0b00000110) == 0b00000100) {
                return;
            }

            /**
             * 对疑问的处理
             */
            else if ((mineMap[row][col] & 0b00000111) == 0b00000111) {

                // 显示雷
                mineMap[row][col] -= 0b00000100;

                // 记录一些数据
                this.ops_fail(row, col);
            }

            /**
             * 踩雷了， 这个地方计算一次失误，然后标识为红旗
             */
            else if ((mineMap[row][col] & 0b00000001) == 0b00000001) {

                // 显示雷
                mineMap[row][col] += 0b00000010;

                // 记录一些数据
                this.ops_fail(row, col);
            }

            /**
             * 对疑问的处理
             */
            else if ((mineMap[row][col] & 0b00000111) == 0b00000110) {

                // 显示雷
                mineMap[row][col] -= 0b00000100;

                // 记录一些数据
                this.ops_success(row, col);
            }

            /**
             * 未开的区域
             */
            else {
                // 记录一些数据
                this.ops_success(row, col);
            }
        }

        /**
         * 这个分支是右键，标识为类，是否需要判断失误
         */
        else if (e.getButton() == 3) {

            /**
             * 未开的雷
             */
            if ((mineMap[row][col] & 0b00000111) == 0b00000001) {
                // 显示雷
                mineMap[row][col] += 0b00000010;
                this.ops_fail(row, col);
            }

            /**
             * 没有类 - 也没操作过
             */
            else if ((mineMap[row][col] & 0b00000111) == 0b00000000) {
                mineMap[row][col] += 0b00000100;
                this.ops_success(row, col);
            }

            // /**
            // * 对旗子有疑问
            // */
            // if ((mineMap[row][col] & 0b00000110) == 0b00000100) {
            // mineMap[row][col] += 0b00000010;
            // this.ops_delFlag(row, col);
            // }
            //
            // /**
            // * 减掉
            // */
            // else if ((mineMap[row][col] & 0b00000110) == 0b00000110) {
            // mineMap[row][col] -= 0b00000110;
            // }
            //
            // /**
            // * 加上旗子
            // */
            // else {
            // mineMap[row][col] += 0b00000100;
            // this.ops_addFlag(row, col);
            // }
        }

        /**
         * 重绘雷区
         */
        this.repaint();
    }

    // 级联操作
    private void openWhiteOption(int x, int y) {
        int rows = this.game.getLevel().getRow();
        int cols = this.game.getLevel().getCol();
        int[][] mineMap = this.game.getMineMap();
        int state = mineMap[x][y];

        if ((state & 0b1) == 1 || (state & 0b110) == 0b010 || (state & 0b110) == 0b100 || (state & 0b110) == 0b110) {
            return;
        }

        mineMap[x][y] += 0b10;

        if ((state >>> 3) == 0) {
            if (x - 1 >= 0) {
                openWhiteOption(x - 1, y);
                if (y - 1 >= 0) {
                    openWhiteOption(x - 1, y - 1);
                }

                if (y + 1 < cols) {
                    openWhiteOption(x - 1, y + 1);
                }
            }

            if (x + 1 < rows) {
                openWhiteOption(x + 1, y);

                if (y - 1 >= 0) {
                    openWhiteOption(x + 1, y - 1);
                }

                if (y + 1 < cols) {
                    openWhiteOption(x + 1, y + 1);
                }
            }

            if (y - 1 >= 0) {
                openWhiteOption(x, y - 1);
            }

            if (y + 1 < cols) {
                openWhiteOption(x, y + 1);
            }
        }
    }

    // ---------------- 点击雷区 操作反馈 开始 ----------------------

    /**
     * 操作成功
     */
    private void ops_success(int row, int col) {
        openWhiteOption(row, col);
        new BlastAudio().start();
        this.gameField.feedbackMineResult(true);
    }

    /**
     * 踩到雷了
     */
    private void ops_fail(int row, int col) {
        int x = col * size + 40;
        int y = row * size + 50;
        this.addExplode(x, y);
        this.gameField.feedbackMineResult(false);
    }

    // /**
    // * 添加旗子(没有这些)
    // */
    // private void ops_addFlag(int row, int col) {
    // this.gameField.feedbackMineResult(null);
    // }
    //
    // /**
    // * 删除旗子(没有这些)
    // */
    // private void ops_delFlag(int row, int col) {
    // this.gameField.feedbackMineResult(null);
    // }

    // ---------------- 点击雷区 操作反馈 结束----------------------

    /**
     * 删除指定的爆炸点
     * 
     * @param explode
     */
    public void addExplode(int x, int y) {
        this.explodes.add(new ExplodeField(this, x, y));
    }

    /**
     * 绘制爆炸效果
     */
    private void doPaintExplodes(Graphics g) {
        for (ExplodeField field : this.explodes) {
            field.paint(g);
        }
    }

    /**
     * 删除指定的爆炸点
     * 
     * @param explode
     */
    public void removeExplode(ExplodeField explode) {
        this.explodes.remove(explode);
    }

    /**
     * 结束绘制任务
     */
    public void destory() {
        this.running = false;
    }

    /**
     * 点击正确的音效
     * 
     * @author lifeng
     * @date 2021/05/15
     */
    public class BlastAudio extends GameAudio {
        public BlastAudio() {
            super("blast.wav");
        }
    }

}
